package racing.ui;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GridLayout;
import java.awt.List;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import java.util.Observable;
import java.util.Observer;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

import racing.bot.Bot;
import racing.car.RacingCar;
import racing.car.RacingCarFactory;
import racing.client.Client;
import racing.client.Message;
import racing.rule.DiceRule;
import racing.rule.RPS;
import racing.rule.RPSRule;
import racing.rule.Rules;
import racing.stage.Stage;
import racing.stage.StageFactory;

/**
 * The user interface of the game.
 * 
 * @author Sarathit Sangtaweep 5510546182
 * @author Veerapat Teeravipark 5510547022
 * @version 2013
 */
public class RacingUI extends JFrame implements Observer {
	
	/**Attribute of the class.*/
	private static final long serialVersionUID = 1L;
	private Client client = new Client("localhost", 16668);
	private ChatUI chatUI;
	private int id = 0;
	private boolean isHost = false;
	private boolean isStart = false;
	private boolean isBot = false;
	private boolean startAll = false;
	private String dice;
	private RPS rps1;
	private RPS rps2;
	private ConnectUI connectui;
	private JButton p1_btnStart;
	private String userName1 = "";
	private String userName2 = "";
	private String selectedStage;
	private Stage stage;
	private String selectedCar;
	private RacingCar car1;
	private RacingCar car2;
	private Rules rule;
	private JLabel[] point1;
	private JLabel[] point2;
	private int[] distance1 = new int[1];
	private int[] distance2 = new int[1];
	private Integer[][] stageBlock;
	private boolean booster1IsOn = false;
	private boolean booster2IsOn = false;
	private int bTime1 = 0;
	private int cTime1 = 0;
	private int bTime2 = 0;
	private int cTime2 = 0;
	private int[] lap1 = { 1 };
	private int[] lap2 = { 1 };
	private JLabel lap1_label;
	private JLabel lap2_label;

	private Bot bot;
	int allBlockPath;

	private ImageIcon normal_surface;
	private ImageIcon nothing;
	private ImageIcon imCar1;
	private ImageIcon imCar2;

	private JTextField p2_nameText;
	private JButton p2_withBotButton;
	private JButton p2_onlineButton;
	private JButton p2_createButton;
	private JButton p2_joinButton;

	private JButton p3_selectForward;
	private JButton p3_selectBackward;
	private JLabel p3_stage;
	private JLabel p3_stageDescription;
	private JButton p3_btnOk;
	private String[] allStage;
	private int numStage = 0;

	private JButton p4_selectForward;
	private JButton p4_selectBackward;
	private JButton p4_btnOk;
	private JLabel p4_car;
	private JLabel p4_carDescription;
	private String[] allCar;
	private int numCar = 0;

	private JButton p5_selectRPS;
	private JButton p5_selectDice;

	private JButton p6_1btnBooster;
	private JProgressBar p6_1progressBar;
	private JButton p6_2btnBooster;
	private JProgressBar p6_2progressBar;
	private JLabel p6_user1Result_label;
	private JLabel p6_user2Result_label;
	private JPanel p6_panelStage;
	private JPanel p6_buttons;
	private JButton rollButton;
	private JButton rockButton;
	private JButton paperButton;
	private JButton scissorsButton;

	private JPanel containerPanel;
	private JPanel menuPanel;
	private JPanel page2Panel;
	private JPanel page3Panel;
	private JPanel page4Panel;
	private JPanel page5Panel;
	private JPanel page6Panel;
	private JPanel page7Panel;
	private List p6_battleLogField;

	Font font;

	/**
	 * Constructor of the class.
	 */
	public RacingUI() {
		super("Racing Game");
		chatUI = new ChatUI();
		chatUI.setPreferredSize(new Dimension(390, 310));
		chatUI.setLocation(900, 100);
		connectui = new ConnectUI(this, chatUI);
		connectui.setPreferredSize(new Dimension(396, 115));
		connectui.setLocation(434, 200);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		initComponent();
	}

	/**
	 * Initialize the components of the class.
	 */
	private void initComponent() {
		setResizable(false);
		Dimension dimension = new Dimension(1024, 768);
		setPreferredSize(dimension);
		setMinimumSize(dimension);
		setMaximumSize(dimension);
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

		URL url1 = this.getClass().getClassLoader()
				.getResource("images/backgroundjr.jpg");
		URL url2 = this.getClass().getClassLoader()
				.getResource("images/dimbackground.jpg");
		ImageIcon bgJR = new ImageIcon(url1);
		ImageIcon bgDim = new ImageIcon(url2);

		containerPanel = new JPanel();
		menuPanel = new ImagePanel(bgJR.getImage());
		page2Panel = new ImagePanel(bgDim.getImage());
		page3Panel = new ImagePanel(bgDim.getImage());
		page4Panel = new ImagePanel(bgDim.getImage());
		page5Panel = new ImagePanel(bgDim.getImage());
		page6Panel = new ImagePanel(bgDim.getImage());
		page7Panel = new ImagePanel(bgDim.getImage());

		// p1 components
		p1_btnStart = new JButton();

		// p2 components
		p2_nameText = new JTextField();
		p2_withBotButton = new JButton();
		p2_onlineButton = new JButton();
		p2_createButton = new JButton();
		p2_createButton.setEnabled(false);
		p2_joinButton = new JButton();
		p2_joinButton.setEnabled(false);

		// p3 components
		p3_selectForward = new JButton();
		p3_selectBackward = new JButton();
		p3_stageDescription = new JLabel();
		p3_btnOk = new JButton();

		// p4 components
		p4_selectForward = new JButton();
		p4_selectBackward = new JButton();
		p4_btnOk = new JButton();

		// p5 components
		p5_selectRPS = new JButton();
		p5_selectDice = new JButton();

		containerPanel.setLayout(new CardLayout());

		// icon
		normal_surface = new ImageIcon(this.getClass().getResource(
				"/images/normal_surface.png"));
		nothing = new ImageIcon(this.getClass().getResource(
				"/images/nothing.png"));

		try {
			font = Font.createFont(NORMAL, this.getClass().getClassLoader()
					.getResourceAsStream("fonts/TT0952M_.TTF"));
			font = font.deriveFont(Font.PLAIN);
			font = font.deriveFont(50.0f);
		} catch (FontFormatException | IOException e2) {
			font = new Font("Tahoma", Font.PLAIN, 50);
		}

		initPage1();
		initPage2();
		initPage3();
		initPage4();
		initPage5();

		getContentPane().add(containerPanel, BorderLayout.CENTER);

	}

	/**
	 * Run the program.
	 */
	public void run() {
		pack();
		setVisible(true);
	}

	/**
	 * Return to the previous page.
	 */
	private void returnActionPerformed() {
		CardLayout cl = (CardLayout) (containerPanel.getLayout());
		cl.previous(containerPanel);
	}

	/**
	 * Go to the next page.
	 */
	private void nextActionPerformed() {
		CardLayout cl = (CardLayout) (containerPanel.getLayout());
		cl.next(containerPanel);
	}

	/**
	 * Initialize and create the components in page1.
	 */
	public void initPage1() {
		// initialize page 1
		p1_btnStart.setText("Start Game");
		p1_btnStart.setFont(font);
		p1_btnStart.setForeground(Color.WHITE);
		p1_btnStart.setBackground(Color.BLACK);
		p1_btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				nextActionPerformed();
			}
		});

		JButton btnHowToPlay = new JButton("How to play");
		btnHowToPlay.setFont(font.deriveFont(20.00f));
		btnHowToPlay.setForeground(Color.WHITE);
		btnHowToPlay.setBackground(Color.BLACK);

		btnHowToPlay.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				String htp = "This is the game of racing car by rule\n"
						+ "   There are two rules which is RPS and Dice.\n"
						+ "   > RPS is from Rock Paper Scissors : Users have to play Rock Paper Scissors to decide who is the winner.\n"
						+ "   > Dice : Users will roll the dices, comparing the number from the dice to decide who is the winner.\n\n"
						+ "   The winner's car will move according to the car's speed.\n"
						+ "   (If the rule is Dice, the car will get bonus speed from the different of the dices too.)\n\n"
						+ "Each car has different status which is\n"
						+ "   > Speed : Normal speed of the car.\n"
						+ "   > BoosterSpeed : Turbo speed of the car which user can use when the cooldown is done.\n"
						+ "      (By clicking the button.)\n"
						+ "   > BoosterCooldown : Cooldown of the booster, the time when the booster will be ready to use again.\n"
						+ "   > BoosterTime : The time that booster can last in each use.\n\n"
						+ "A person who get 3 laps first will win the game!\n\n"
						+ "Have Fun!";
				JOptionPane.showMessageDialog(null, htp, "How to play",
						JOptionPane.PLAIN_MESSAGE);
			}

		});

		GroupLayout menuPanelLayout = new GroupLayout(menuPanel);
		menuPanelLayout.setHorizontalGroup(menuPanelLayout
				.createParallelGroup(Alignment.LEADING)
				.addGroup(
						menuPanelLayout.createSequentialGroup().addGap(364)
								.addComponent(p1_btnStart)
								.addContainerGap(399, Short.MAX_VALUE))
				.addGroup(
						Alignment.TRAILING,
						menuPanelLayout.createSequentialGroup()
								.addContainerGap(905, Short.MAX_VALUE)
								.addComponent(btnHowToPlay).addGap(24)));
		menuPanelLayout.setVerticalGroup(menuPanelLayout.createParallelGroup(
				Alignment.TRAILING).addGroup(
				menuPanelLayout.createSequentialGroup()
						.addContainerGap(616, Short.MAX_VALUE)
						.addComponent(p1_btnStart).addGap(17)
						.addComponent(btnHowToPlay).addContainerGap()));
		menuPanel.setLayout(menuPanelLayout);
		containerPanel.add(menuPanel, "card1");
		// ending initialize page 1
	}

	/**
	 * Initialize and create the components in page2.
	 */
	public void initPage2() {
		// initialize page 2
		page2Panel.setBackground(Color.BLACK);

		p2_nameText.setFont(font);

		p2_withBotButton.setFont(font);
		p2_withBotButton.setForeground(Color.WHITE);
		p2_withBotButton.setBackground(Color.BLACK);
		p2_withBotButton.setText("Play With Bot!");
		p2_withBotButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				if (!p2_nameText.getText().trim().equalsIgnoreCase("")
						&& p2_nameText.getText().length() <= 6) {
					if (client.isConnected()) {
						try {
							client.closeConnection();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					bot = new Bot();
					car2 = bot.randomCar();
					imCar2 = new ImageIcon(this.getClass().getResource(
							"/images/inField" + car2.getName() + ".png"));
					isStart = true;
					isBot = true;
					userName1 = p2_nameText.getText();
					userName2 = "bot";
					nextActionPerformed();
				} else {
					JOptionPane
							.showMessageDialog(
									null,
									"Please enter the name which is not more than 6 characters",
									"Announce", JOptionPane.WARNING_MESSAGE);
					p2_nameText.setText("");
					p2_nameText.requestFocus();
				}
			}
		});

		p2_onlineButton.setFont(font);
		p2_onlineButton.setText("Connect to Server");
		p2_onlineButton.setForeground(Color.WHITE);
		p2_onlineButton.setBackground(Color.BLACK);
		p2_onlineButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				connectui.run();
			}
		});

		p2_createButton.setFont(font);
		p2_createButton.setText("Create Room Online!");
		p2_createButton.setForeground(Color.WHITE);
		p2_createButton.setBackground(Color.BLACK);
		p2_createButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				if (!p2_nameText.getText().trim().equalsIgnoreCase("")) {
					try {
						client.sendToServer(new Message("create room"));
					} catch (IOException e) {
						e.printStackTrace();
					}
					if (client.isConnected()) {
						userName1 = p2_nameText.getText();
						isHost = true;
						nextActionPerformed();
					}
				} else {
					JOptionPane
							.showMessageDialog(
									null,
									"Please enter the name which is not more than 6 characters",
									"Announce", JOptionPane.WARNING_MESSAGE);
					p2_nameText.setText("");
					p2_nameText.requestFocus();
				}
			}
		});

		p2_joinButton.setFont(font);
		p2_joinButton.setText("Join Room Online!");
		p2_joinButton.setForeground(Color.WHITE);
		p2_joinButton.setBackground(Color.BLACK);
		p2_joinButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				if (!p2_nameText.getText().trim().equalsIgnoreCase("")) {
					try {
						client.sendToServer(new Message("join room"));
					} catch (IOException e) {
						e.printStackTrace();
					}
					if (client.isConnected()) {
						userName1 = p2_nameText.getText();
						nextActionPerformed();
						nextActionPerformed();
						try {
							client.sendToServer(new Message("setName",
									userName1, id));
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				} else {
					JOptionPane
							.showMessageDialog(
									null,
									"Please enter the name which is not more than 6 characters",
									"Announce", JOptionPane.WARNING_MESSAGE);
					p2_nameText.setText("");
					p2_nameText.requestFocus();
				}
			}
		});

		Panel p2_buttons = new Panel(new GridLayout(5, 1, 20, 20));
		p2_buttons.add(p2_nameText);
		p2_buttons.add(p2_withBotButton);
		p2_buttons.add(p2_onlineButton);
		p2_buttons.add(p2_createButton);
		p2_buttons.add(p2_joinButton);
		GroupLayout page2Layout = new GroupLayout(page2Panel);
		page2Panel.setLayout(page2Layout);
		page2Layout.setHorizontalGroup(page2Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page2Layout.createSequentialGroup()
						.addContainerGap(340, Short.MAX_VALUE)
						.addComponent(p2_buttons).addGap(280)));
		page2Layout.setVerticalGroup(page2Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page2Layout.createSequentialGroup()
						.addContainerGap(611, Short.MAX_VALUE)
						.addComponent(p2_buttons).addGap(150)));
		containerPanel.add(page2Panel, "card2");

		// ending initialize page 2
	}

	/**
	 * Initialize and create the components in page3.
	 */
	public void initPage3() {
		// initialize page 3_normal page
		p3_stage = new JLabel();

		// default stage
		p3_stage.setIcon(new ImageIcon(this.getClass().getResource(
				"/images/Racing Field.jpg")));
		p3_stageDescription.setIcon(new ImageIcon(this.getClass().getResource(
				"/images/Racing FieldDescription.jpg")));
		numStage = 1;
		allStage = StageFactory.getInstance().getAllStage();

		p3_selectBackward.setFont(font);
		p3_selectBackward.setText("<");
		p3_selectBackward.setForeground(Color.WHITE);
		p3_selectBackward.setBackground(Color.BLACK);
		p3_selectBackward.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				numStage--;
				if (numStage == -1)
					numStage = allStage.length - 1;
				p3_stage.setIcon(new ImageIcon(this.getClass().getResource(
						"/images/" + allStage[numStage] + ".jpg")));
				p3_stageDescription.setIcon(new ImageIcon(this.getClass()
						.getResource(
								"/images/" + allStage[numStage]
										+ "Description.jpg")));
			}
		});

		p3_selectForward.setFont(font);
		p3_selectForward.setText(">");
		p3_selectForward.setForeground(Color.WHITE);
		p3_selectForward.setBackground(Color.BLACK);
		p3_selectForward.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				numStage++;
				if (numStage > allStage.length - 1)
					numStage = 0;
				p3_stage.setIcon(new ImageIcon(this.getClass().getResource(
						"/images/" + allStage[numStage] + ".jpg")));
				p3_stageDescription.setIcon(new ImageIcon(this.getClass()
						.getResource(
								"/images/" + allStage[numStage]
										+ "Description.jpg")));
			}
		});

		p3_btnOk.setFont(font);
		p3_btnOk.setText("OK!");
		p3_btnOk.setForeground(Color.WHITE);
		p3_btnOk.setBackground(Color.BLACK);
		p3_btnOk.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				selectedStage = allStage[numStage];
				if (client.isConnected()) {
					try {
						client.sendToServer(new Message("setStage",
								selectedStage, id));
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				stage = StageFactory.getInstance().createStage(selectedStage);
				nextActionPerformed();
			}
		});

		JLabel txtStage = new JLabel("Stage Selection");
		txtStage.setFont(font);

		JPanel p3_panel = new JPanel(new BorderLayout());
		p3_panel.setOpaque(false);
		JPanel p3_upper = new JPanel(new BorderLayout());
		p3_upper.setOpaque(false);
		p3_upper.add(txtStage, BorderLayout.WEST);
		p3_upper.add(p3_stageDescription, BorderLayout.EAST);

		JPanel p3_center = new JPanel(new BorderLayout());
		p3_center.setOpaque(false);
		JPanel p3_center_west = new JPanel(new BorderLayout());
		JPanel p3_center_east = new JPanel(new BorderLayout());
		p3_center_west.add(p3_selectBackward, BorderLayout.CENTER);
		p3_center_east.add(p3_selectForward, BorderLayout.CENTER);
		p3_center.add(p3_center_west, BorderLayout.WEST);
		p3_center.add(p3_center_east, BorderLayout.EAST);
		p3_stage.setVerticalAlignment(SwingConstants.CENTER);
		p3_stage.setHorizontalAlignment(SwingConstants.CENTER);
		p3_center.add(p3_stage, BorderLayout.CENTER);

		JPanel p3_lower = new JPanel(new BorderLayout());
		p3_lower.setOpaque(false);
		p3_lower.add(p3_btnOk, BorderLayout.EAST);

		p3_panel.add(p3_upper, BorderLayout.NORTH);
		p3_panel.add(p3_center, BorderLayout.CENTER);
		p3_panel.add(p3_lower, BorderLayout.SOUTH);

		GroupLayout page3Layout = new GroupLayout(page3Panel);
		page3Panel.setLayout(page3Layout);
		page3Layout.setHorizontalGroup(page3Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page3Layout.createSequentialGroup().addComponent(p3_panel)));
		page3Layout.setVerticalGroup(page3Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page3Layout.createSequentialGroup().addComponent(p3_panel)));

		containerPanel.add(page3Panel, "card3");
		// ending initialize page 3_normal page

	}

	/**
	 * Initialize and create the components in page4.
	 */
	public void initPage4() {
		// initialize page 4_normal page
		p4_car = new JLabel();
		p4_carDescription = new JLabel();

		// default car
		p4_car.setIcon(new ImageIcon(this.getClass().getResource(
				"/images/1JaVaCar.png")));
		p4_carDescription.setIcon(new ImageIcon(this.getClass().getResource(
				"/images/1JaVaCarDescription.jpg")));
		allCar = RacingCarFactory.getInstance().getAllCar();
		numCar = 0;
		p4_selectBackward.setFont(font);
		p4_selectBackward.setText("<");
		p4_selectBackward.setForeground(Color.WHITE);
		p4_selectBackward.setBackground(Color.BLACK);
		p4_selectBackward.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				numCar--;
				if (numCar == -1)
					numCar = allCar.length - 1;
				p4_car.setIcon(new ImageIcon(this.getClass().getResource(
						"/images/" + allCar[numCar] + ".png")));
				p4_carDescription.setIcon(new ImageIcon(
						this.getClass()
								.getResource(
										"/images/" + allCar[numCar]
												+ "Description.jpg")));
			}
		});

		p4_selectForward.setFont(font);
		p4_selectForward.setText(">");
		p4_selectForward.setForeground(Color.WHITE);
		p4_selectForward.setBackground(Color.BLACK);
		p4_selectForward.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				numCar++;
				if (numCar > allCar.length - 1)
					numCar = 0;
				p4_car.setIcon(new ImageIcon(this.getClass().getResource(
						"/images/" + allCar[numCar] + ".png")));
				p4_carDescription.setIcon(new ImageIcon(
						this.getClass()
								.getResource(
										"/images/" + allCar[numCar]
												+ "Description.jpg")));
			}
		});

		p4_btnOk.setFont(font);
		p4_btnOk.setText("OK!");
		p4_btnOk.setForeground(Color.WHITE);
		p4_btnOk.setBackground(Color.BLACK);
		p4_btnOk.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				selectedCar = allCar[numCar];
				if (client.isConnected()) {
					try {
						client.sendToServer(new Message("setName", userName1,
								id));
						client.sendToServer(new Message("setCar", selectedCar,
								id));
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				car1 = RacingCarFactory.getInstance().createCar(selectedCar);
				imCar1 = new ImageIcon(this.getClass().getResource(
						"/images/inField" + car1.getName() + ".png"));
				if (isStart && !isHost && !isBot) {
					try {
						client.sendToServer(new Message("startAll"));
					} catch (IOException e) {
						e.printStackTrace();
					}
					chatUI.setName(userName1);
					chatUI.run();
					initPage6(rule);
					nextActionPerformed();
					nextActionPerformed();
				} else if (isHost || isBot) {
					nextActionPerformed();
				} else {
					JOptionPane.showMessageDialog(null, "Waiting for host.",
							"Announce", JOptionPane.WARNING_MESSAGE);
				}
			}
		});

		JLabel txtCar = new JLabel("Car Selection");
		txtCar.setFont(font);

		JPanel p4_panel = new JPanel(new BorderLayout());
		p4_panel.setOpaque(false);

		JPanel p4_upper = new JPanel(new BorderLayout());
		p4_upper.setOpaque(false);
		p4_upper.add(txtCar, BorderLayout.WEST);
		p4_upper.add(p4_carDescription, BorderLayout.EAST);

		JPanel p4_center = new JPanel(new BorderLayout());
		p4_center.setOpaque(false);
		Panel p4_center_west = new Panel(new BorderLayout());
		Panel p4_center_east = new Panel(new BorderLayout());
		p4_center_west.add(p4_selectBackward, BorderLayout.CENTER);
		p4_center_east.add(p4_selectForward, BorderLayout.CENTER);
		p4_center.add(p4_center_west, BorderLayout.WEST);
		p4_center.add(p4_center_east, BorderLayout.EAST);
		p4_car.setVerticalAlignment(SwingConstants.CENTER);
		p4_car.setHorizontalAlignment(SwingConstants.CENTER);
		p4_center.add(p4_car, BorderLayout.CENTER);

		JPanel p4_lower = new JPanel(new BorderLayout());
		p4_lower.setOpaque(false);
		p4_lower.add(p4_btnOk, BorderLayout.EAST);

		p4_panel.add(p4_upper, BorderLayout.NORTH);
		p4_panel.add(p4_center, BorderLayout.CENTER);
		p4_panel.add(p4_lower, BorderLayout.SOUTH);

		GroupLayout page4Layout = new GroupLayout(page4Panel);
		page4Panel.setLayout(page4Layout);
		page4Layout.setHorizontalGroup(page4Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page4Layout.createSequentialGroup().addComponent(p4_panel)));
		page4Layout.setVerticalGroup(page4Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page4Layout.createSequentialGroup().addComponent(p4_panel)));

		containerPanel.add(page4Panel, "card4");
		// ending initialize page 4_normal page
	}

	/**
	 * Initialize and create the components in page5.
	 */
	public void initPage5() {
		// initialize page 5_normal page

		p5_selectRPS.setFont(font);
		p5_selectRPS.setText("RPS");
		p5_selectRPS.setForeground(Color.WHITE);
		p5_selectRPS.setBackground(Color.BLACK);
		p5_selectRPS.setPreferredSize(new Dimension(300, 300));
		p5_selectRPS.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				rule = new RPSRule();
				if (isHost) {
					try {
						client.sendToServer(new Message("setRule", "RPS", id));
						client.sendToServer(new Message("start", id));
					} catch (IOException e) {
						e.printStackTrace();
					}
					p5_selectDice.setEnabled(false);
				}
				if (isStart) {
					if (client.isConnected()) {
						try {
							client.sendToServer(new Message("startAll"));
						} catch (IOException e) {
							e.printStackTrace();
						}
						chatUI.setName(userName1);
						chatUI.run();
					}
					initPage6(rule);
					nextActionPerformed();
				} else {
					JOptionPane.showMessageDialog(null,
							"Please waiting for client", "Announce",
							JOptionPane.WARNING_MESSAGE);
				}
			}
		});

		p5_selectDice.setFont(font);
		p5_selectDice.setText("Dice");
		p5_selectDice.setForeground(Color.WHITE);
		p5_selectDice.setBackground(Color.BLACK);
		p5_selectDice.setPreferredSize(new Dimension(300, 300));
		p5_selectDice.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				rule = new DiceRule();
				if (isHost) {
					try {
						client.sendToServer(new Message("setRule", "DICE", id));
						client.sendToServer(new Message("start", id));
					} catch (IOException e) {
						e.printStackTrace();
					}
					p5_selectRPS.setEnabled(false);
				}
				if (isStart) {
					if (client.isConnected()) {
						try {
							client.sendToServer(new Message("startAll"));
						} catch (IOException e) {
							e.printStackTrace();
						}
						chatUI.setName(userName1);
						chatUI.run();
					}
					initPage6(rule);
					nextActionPerformed();
				} else {
					JOptionPane.showMessageDialog(null,
							"Please waiting for client", "Announce",
							JOptionPane.WARNING_MESSAGE);
				}
			}
		});

		JLabel txtRule = new JLabel("Rule Selection");
		txtRule.setFont(font);

		BorderLayout p5Border = new BorderLayout();
		p5Border.setVgap(165);
		JPanel p5_panel = new JPanel(p5Border);
		p5_panel.setOpaque(false);

		JPanel p5_upper = new JPanel(new BorderLayout());
		p5_upper.add(txtRule, BorderLayout.WEST);
		p5_upper.setOpaque(false);

		JPanel p5_center = new JPanel(new FlowLayout());
		p5_center.setOpaque(false);
		p5_center.add(p5_selectRPS);
		p5_center.add(p5_selectDice);

		p5_panel.add(p5_upper, BorderLayout.NORTH);
		p5_panel.add(p5_center, BorderLayout.CENTER);

		GroupLayout page5Layout = new GroupLayout(page5Panel);
		page5Panel.setLayout(page5Layout);
		page5Layout.setHorizontalGroup(page5Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page5Layout.createSequentialGroup().addComponent(p5_panel)));
		page5Layout.setVerticalGroup(page5Layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				GroupLayout.Alignment.TRAILING,
				page5Layout.createSequentialGroup().addComponent(p5_panel)));

		containerPanel.add(page5Panel, "card5");
		// ending initialize page 5_normal page
	}

	/**
	 * Initialize and create the components in page6.
	 * @param playRule the rule for playing the game.
	 */
	public void initPage6(Rules playRule) {
		// initialize page 6_normal page

		Panel user1Panel = new Panel();
		user1Panel.setLayout(new BorderLayout());

		Panel user1_center = new Panel(new GridLayout(5, 2));
		user1_center.add(new JLabel("Name : " + userName1));
		user1_center.add(new JLabel(""));
		user1_center.add(new JLabel("Stage : " + selectedStage));
		user1_center.add(new JLabel(""));
		user1_center.add(new JLabel("Car : " + car1.getName()));
		user1_center.add(new JLabel(""));
		user1_center.add(new JLabel("Speed : " + car1.getSpeed()));
		user1_center.add(new JLabel("B-Speed : " + car1.getBoosterSpeed()));
		user1_center
				.add(new JLabel("B-Cooldown : " + car1.getBoosterCooldown()));
		user1_center.add(new JLabel("B-Time : " + car1.getBoosterTime()));
		Panel user1_lower = new Panel(new BorderLayout());
		p6_1btnBooster = new JButton("Booster");
		p6_1progressBar = new JProgressBar();
		p6_1progressBar.setStringPainted(true);
		p6_1progressBar.setForeground(Color.orange);

		user1_lower.add(p6_1btnBooster, BorderLayout.WEST);
		user1_lower.add(p6_1progressBar);
		user1Panel.add(user1_center, BorderLayout.CENTER);
		user1Panel.add(user1_lower, BorderLayout.SOUTH);

		Panel user2Panel = new Panel();
		user2Panel.setLayout(new BorderLayout());

		Panel user2_center = new Panel(new GridLayout(5, 2));
		user2_center.add(new JLabel("Name : " + userName2));
		user2_center.add(new JLabel(""));
		user2_center.add(new JLabel("Stage : " + selectedStage));
		user2_center.add(new JLabel(""));
		user2_center.add(new JLabel("Car : " + car2.getName()));
		user2_center.add(new JLabel(""));
		user2_center.add(new JLabel("Speed : " + car2.getSpeed()));
		user2_center.add(new JLabel("B-Speed : " + car2.getBoosterSpeed()));
		user2_center
				.add(new JLabel("B-Cooldown : " + car2.getBoosterCooldown()));
		user2_center.add(new JLabel("B-Time : " + car2.getBoosterTime()));
		Panel user2_lower = new Panel(new BorderLayout());
		p6_2btnBooster = new JButton("Booster");
		p6_2progressBar = new JProgressBar();
		p6_2progressBar.setStringPainted(true);
		p6_2progressBar.setForeground(Color.orange);

		user2_lower.add(p6_2btnBooster, BorderLayout.WEST);
		user2_lower.add(p6_2progressBar);
		user2Panel.add(user2_center, BorderLayout.CENTER);
		user2Panel.add(user2_lower, BorderLayout.SOUTH);

		Panel p6_duelResult = new Panel(new GridLayout(1, 3));

		Panel p6_user1Result = new Panel(new BorderLayout());
		p6_user1Result_label = new JLabel();
		p6_user1Result_label.setFont(new Font("Tahoma", Font.PLAIN, 80));
		p6_user1Result_label.setHorizontalAlignment(SwingConstants.CENTER);
		p6_user1Result_label.setVerticalAlignment(SwingConstants.CENTER);

		lap1_label = new JLabel(userName1 + "  " + lap1[0] + "/3 LAP");
		lap2_label = new JLabel(userName2 + "  " + lap2[0] + "/3 LAP");

		Panel p6_vsResult = new Panel(new BorderLayout());
		JLabel p6_vsRule_label = new JLabel(rule.toString());
		JLabel p6_vsResult_label = new JLabel("VS");
		p6_vsResult_label.setFont(new Font("Tahoma", Font.PLAIN, 80));
		p6_vsResult_label.setHorizontalAlignment(SwingConstants.CENTER);
		p6_vsResult_label.setVerticalAlignment(SwingConstants.CENTER);
		p6_vsResult.setPreferredSize(new Dimension(143, 100));
		p6_vsResult.setBackground(Color.MAGENTA);
		p6_vsResult.add(p6_vsResult_label, BorderLayout.CENTER);

		p6_vsRule_label.setHorizontalAlignment(SwingConstants.CENTER);
		p6_vsRule_label.setVerticalAlignment(SwingConstants.CENTER);
		p6_vsResult.add(p6_vsRule_label, BorderLayout.NORTH);

		Panel p6_user2Result = new Panel(new BorderLayout());
		p6_user2Result_label = new JLabel();
		p6_user2Result_label.setFont(new Font("Tahoma", Font.PLAIN, 80));
		p6_user2Result_label.setHorizontalAlignment(SwingConstants.CENTER);
		p6_user2Result_label.setVerticalAlignment(SwingConstants.CENTER);

		p6_user1Result.add(lap1_label, BorderLayout.NORTH);
		p6_user1Result.add(p6_user1Result_label, BorderLayout.SOUTH);
		p6_user1Result.setPreferredSize(new Dimension(143, 100));
		p6_user1Result.setBackground(Color.RED);
		p6_user2Result.add(lap2_label, BorderLayout.NORTH);
		p6_user2Result.add(p6_user2Result_label, BorderLayout.SOUTH);
		p6_user2Result.setPreferredSize(new Dimension(143, 100));
		p6_user2Result.setBackground(Color.BLUE);
		p6_duelResult.add(p6_user1Result);
		p6_duelResult.add(p6_vsResult);
		p6_duelResult.add(p6_user2Result);

		JPanel p6_bigContainer = new JPanel(new BorderLayout());
		p6_bigContainer.setOpaque(false);
		p6_buttons = new JPanel();
		p6_buttons.setOpaque(false);

		Panel p6_1container = new Panel(new BorderLayout());
		p6_1container.add(user1Panel, BorderLayout.WEST);
		p6_1container.setBackground(new Color(60, 255, 100));

		Panel p6_2container = new Panel(new BorderLayout());
		p6_2container.add(user2Panel, BorderLayout.WEST);
		p6_2container.setBackground(new Color(60, 255, 100));

		stageBlock = stage.getBlocks();
		p6_panelStage = new JPanel(new GridLayout(stageBlock.length,
				stageBlock[0].length));
		p6_panelStage.setOpaque(false);
		// number of the block for users.
		allBlockPath = stageBlock.length * stageBlock[0].length
				- (stageBlock.length - 4) * (stageBlock[0].length - 4) - 16;
		point1 = new JLabel[allBlockPath / 2];
		point2 = new JLabel[allBlockPath / 2];
		addPointToBlock();

		bTime1 = car1.getBoosterTime();
		cTime1 = car1.getBoosterCooldown();
		bTime2 = car2.getBoosterTime();
		cTime2 = car2.getBoosterCooldown();
		p6_1progressBar.setMaximum(cTime1);
		p6_1btnBooster.setText("CoolTime : " + cTime1);
		p6_1btnBooster.setPreferredSize(new Dimension(120, 25));
		p6_2btnBooster.setEnabled(false);
		p6_2progressBar.setMaximum(cTime2);
		p6_2btnBooster.setText("CoolTime : " + cTime2);
		p6_2btnBooster.setPreferredSize(new Dimension(120, 25));
		p6_2btnBooster.setEnabled(false);

		p6_1btnBooster.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (cTime1 == 0) {
					booster1IsOn = true;
					p6_1btnBooster.setEnabled(false);
					p6_1btnBooster.setText("Booster Left : " + bTime1);
					if (client.isConnected()) {
						try {
							client.sendToServer(new Message("clickBooster", id));
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}
				}
			}
		});
		point1[distance1[0]].setIcon(imCar1);
		point2[distance2[0]].setIcon(imCar2);

		// play dice rule.
		if (playRule.getClass().equals(DiceRule.class)) {
			rollButton = new JButton("Roll!");
			rollButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if (isBot) {
						p6_user1Result_label.setText("" + bot.randomPlayDice());
						p6_user2Result_label.setText("" + bot.randomPlayDice());
						int different = Integer.parseInt(p6_user1Result_label
								.getText())
								- Integer.parseInt(p6_user2Result_label
										.getText());
						if (different > 0) // user 1 win.
							move(point1, distance1, booster1IsOn, car1, imCar1,
									Math.abs(different), lap1, lap1_label,
									userName1);
						else if (different < 0) // user 2 win.
							move(point2, distance2, booster2IsOn, car2, imCar2,
									Math.abs(different), lap2, lap2_label,
									userName2);
						else
							p6_battleLogField.add("DRAW");
						timePass();
					} else if (client.isConnected() && startAll) {
						dice = bot.randomPlayDice() + "";
						rollButton.setEnabled(false);
						try {
							client.sendToServer(new Message("sendDice", dice,
									id));
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					} else {
						if (isHost) {
							JOptionPane.showMessageDialog(null,
									"Waiting for Client", "Announce",
									JOptionPane.WARNING_MESSAGE);
						} else {
							JOptionPane.showMessageDialog(null,
									"Waiting for Server", "Announce",
									JOptionPane.WARNING_MESSAGE);
						}
					}
				}
			});
			p6_buttons.add(rollButton);
		}
		// play RPS rule.
		else {
			GridLayout rpslayout = new GridLayout(3, 1);
			rpslayout.setVgap(5);
			p6_buttons.setLayout(rpslayout);
			rockButton = new JButton("Rock!");
			paperButton = new JButton("Paper!");
			scissorsButton = new JButton("Scissors!");

			rockButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if (isBot) {
						p6_user1Result_label.setIcon(((RPSRule) rule)
								.getImageIcon("Rock"));
						RPS rpsBot = bot.randomPlayRPS();
						p6_user2Result_label.setIcon(((RPSRule) rule)
								.getImageIcon(rpsBot.toString(rpsBot)));
						RPS winner = ((RPSRule) rule).play(RPS.ROCK, rpsBot);
						if (winner == RPS.ROCK) // user 1 win.
							move(point1, distance1, booster1IsOn, car1, imCar1,
									0, lap1, lap1_label, userName1);
						else if (winner == rpsBot) // user 2 win.
							move(point2, distance2, booster2IsOn, car2, imCar2,
									0, lap2, lap2_label, userName2);
						else
							p6_battleLogField.add("DRAW");
						timePass();
					} else if (client.isConnected() && startAll) {
						rps1 = RPS.ROCK;
						rockButton.setEnabled(false);
						paperButton.setEnabled(false);
						scissorsButton.setEnabled(false);
						try {
							client.sendToServer(new Message("sendRPS", "Rock",
									id));
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					} else {
						if (isHost) {
							JOptionPane.showMessageDialog(null,
									"Waiting for Client", "Announce",
									JOptionPane.WARNING_MESSAGE);
						} else {
							JOptionPane.showMessageDialog(null,
									"Waiting for Server", "Announce",
									JOptionPane.WARNING_MESSAGE);
						}
					}

				}
			});

			paperButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if (isBot) {
						p6_user1Result_label.setIcon(((RPSRule) rule)
								.getImageIcon("Paper"));
						RPS rpsBot = bot.randomPlayRPS();
						p6_user2Result_label.setIcon(((RPSRule) rule)
								.getImageIcon(rpsBot.toString(rpsBot)));
						RPS winner = ((RPSRule) rule).play(RPS.PAPER, rpsBot);
						if (winner == RPS.PAPER) // user 1 win.
							move(point1, distance1, booster1IsOn, car1, imCar1,
									0, lap1, lap1_label, userName1);
						else if (winner == rpsBot) // user 2 win.
							move(point2, distance2, booster2IsOn, car2, imCar2,
									0, lap2, lap2_label, userName2);
						else
							p6_battleLogField.add("DRAW");
						timePass();
					} else if (client.isConnected() && startAll) {
						rps1 = RPS.PAPER;
						rockButton.setEnabled(false);
						paperButton.setEnabled(false);
						scissorsButton.setEnabled(false);
						try {
							client.sendToServer(new Message("sendRPS", "Paper",
									id));
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					} else {
						if (isHost) {
							JOptionPane.showMessageDialog(null,
									"Waiting for Client", "Announce",
									JOptionPane.WARNING_MESSAGE);
						} else {
							JOptionPane.showMessageDialog(null,
									"Waiting for Server", "Announce",
									JOptionPane.WARNING_MESSAGE);
						}
					}

				}
			});

			scissorsButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if (isBot) {
						p6_user1Result_label.setIcon(((RPSRule) rule)
								.getImageIcon("Scissors"));
						RPS rpsBot = bot.randomPlayRPS();
						p6_user2Result_label.setIcon(((RPSRule) rule)
								.getImageIcon(rpsBot.toString(rpsBot)));
						RPS winner = ((RPSRule) rule)
								.play(RPS.SCISSORS, rpsBot);
						if (winner == RPS.SCISSORS) // user 1 win.
							move(point1, distance1, booster1IsOn, car1, imCar1,
									0, lap1, lap1_label, userName1);
						else if (winner == rpsBot) // user 2 win.
							move(point2, distance2, booster2IsOn, car2, imCar2,
									0, lap2, lap2_label, userName2);
						else
							p6_battleLogField.add("DRAW");
						timePass();
					} else if (client.isConnected() && startAll) {
						rps1 = RPS.SCISSORS;
						rockButton.setEnabled(false);
						paperButton.setEnabled(false);
						scissorsButton.setEnabled(false);
						try {
							client.sendToServer(new Message("sendRPS", "Scissors",
									id));
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					} else {
						if (isHost) {
							JOptionPane.showMessageDialog(null,
									"Waiting for Client", "Announce",
									JOptionPane.WARNING_MESSAGE);
						} else {
							JOptionPane.showMessageDialog(null,
									"Waiting for Server", "Announce",
									JOptionPane.WARNING_MESSAGE);
						}
					}

				}
			});

			p6_buttons.add(rockButton);
			p6_buttons.add(paperButton);
			p6_buttons.add(scissorsButton);
		}

		p6_bigContainer.add(p6_1container, BorderLayout.WEST);
		p6_bigContainer.add(p6_duelResult, BorderLayout.CENTER);
		p6_bigContainer.add(p6_2container, BorderLayout.EAST);

		JLabel lblBattleLog = new JLabel("Battle Log");
		lblBattleLog.setFont(new Font("Tahoma", Font.PLAIN, 20));
		p6_battleLogField = new List();

		GroupLayout page6Layout = new GroupLayout(page6Panel);
		page6Layout
				.setHorizontalGroup(page6Layout
						.createParallelGroup(Alignment.TRAILING)
						.addGroup(
								page6Layout
										.createSequentialGroup()
										.addGroup(
												page6Layout
														.createParallelGroup(
																Alignment.TRAILING,
																false)
														.addGroup(
																page6Layout
																		.createSequentialGroup()
																		.addGap(20)
																		.addComponent(
																				p6_bigContainer,
																				GroupLayout.PREFERRED_SIZE,
																				GroupLayout.DEFAULT_SIZE,
																				GroupLayout.PREFERRED_SIZE))
														.addGroup(
																page6Layout
																		.createSequentialGroup()
																		.addGap(stage
																				.getBlocks()[0].length * 2)
																		.addComponent(
																				p6_panelStage,
																				GroupLayout.PREFERRED_SIZE,
																				stage.getBlocks()[0].length * 20,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED,
																				GroupLayout.DEFAULT_SIZE,
																				Short.MAX_VALUE)
																		.addGroup(
																				page6Layout
																						.createParallelGroup(
																								Alignment.LEADING)
																						.addComponent(
																								lblBattleLog,
																								GroupLayout.PREFERRED_SIZE,
																								138,
																								GroupLayout.PREFERRED_SIZE)
																						.addGroup(
																								page6Layout
																										.createParallelGroup(
																												Alignment.TRAILING)
																										.addComponent(
																												p6_buttons,
																												GroupLayout.PREFERRED_SIZE,
																												103,
																												GroupLayout.PREFERRED_SIZE)
																										.addComponent(
																												p6_battleLogField,
																												GroupLayout.PREFERRED_SIZE,
																												388,
																												GroupLayout.PREFERRED_SIZE)))))
										.addContainerGap(37, Short.MAX_VALUE)));
		page6Layout
				.setVerticalGroup(page6Layout
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								page6Layout
										.createSequentialGroup()
										.addGap(20)
										.addComponent(p6_bigContainer,
												GroupLayout.PREFERRED_SIZE,
												127, GroupLayout.PREFERRED_SIZE)
										.addGroup(
												page6Layout
														.createParallelGroup(
																Alignment.LEADING)
														.addGroup(
																page6Layout
																		.createSequentialGroup()
																		.addGap(75)
																		.addComponent(
																				p6_panelStage,
																				GroupLayout.PREFERRED_SIZE,
																				stage.getBlocks().length * 20,
																				GroupLayout.PREFERRED_SIZE))
														.addGroup(
																page6Layout
																		.createSequentialGroup()
																		.addGap(23)
																		.addComponent(
																				lblBattleLog,
																				GroupLayout.PREFERRED_SIZE,
																				26,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				p6_battleLogField,
																				GroupLayout.PREFERRED_SIZE,
																				370,
																				GroupLayout.PREFERRED_SIZE)))
										.addPreferredGap(
												ComponentPlacement.RELATED, 98,
												Short.MAX_VALUE)
										.addComponent(p6_buttons,
												GroupLayout.PREFERRED_SIZE, 95,
												GroupLayout.PREFERRED_SIZE)
										.addGap(31)));
		page6Panel.setLayout(page6Layout);

		containerPanel.add(page6Panel, "card6");
		// ending initialize page 6_normal page
	}

	/**
	 * Initialize and create the components in page7.
	 * @param winner name of the winner.
	 * @param loser name of the loser.
	 */
	public void initPage7(String winner, String loser) {
		JPanel p7_container = new JPanel(new BorderLayout());
		JPanel p7_userWin = new JPanel(new BorderLayout());
		JPanel p7_userLose = new JPanel(new BorderLayout());
		JPanel p7_userResult = new JPanel(new GridLayout(1, 2));
		p7_container.setOpaque(false);
		p7_userResult.setOpaque(false);

		p7_userWin.setBackground(new Color(238, 44, 44));
		p7_userLose.setBackground(new Color(65, 105, 225));
		JLabel p7_result = new JLabel("Result");
		p7_result.setFont(font);

		JLabel p7_winner = new JLabel("WINNER : " + winner);
		p7_winner.setHorizontalAlignment(SwingConstants.CENTER);
		p7_winner.setVerticalAlignment(SwingConstants.CENTER);
		p7_winner.setFont(font);

		JLabel p7_loser = new JLabel("LOSER : " + loser);
		p7_loser.setHorizontalAlignment(SwingConstants.CENTER);
		p7_loser.setVerticalAlignment(SwingConstants.CENTER);
		p7_loser.setFont(font);

		p7_userWin.add(p7_winner, BorderLayout.CENTER);
		p7_userLose.add(p7_loser, BorderLayout.CENTER);

		p7_container.add(p7_result, BorderLayout.NORTH);
		p7_userResult.add(p7_userWin);
		p7_userResult.add(p7_userLose);
		p7_container.add(p7_userResult, BorderLayout.CENTER);

		GroupLayout page7Layout = new GroupLayout(page7Panel);
		page7Panel.setLayout(page7Layout);
		page7Layout
				.setHorizontalGroup(page7Layout.createParallelGroup(
						GroupLayout.Alignment.LEADING).addGroup(
						GroupLayout.Alignment.TRAILING,
						page7Layout.createSequentialGroup().addComponent(
								p7_container)));
		page7Layout
				.setVerticalGroup(page7Layout.createParallelGroup(
						GroupLayout.Alignment.LEADING).addGroup(
						GroupLayout.Alignment.TRAILING,
						page7Layout.createSequentialGroup().addComponent(
								p7_container)));

		containerPanel.add(page7Panel, "card7");
	}

	/**
	 * Add order of block for the race to the array while creating the stage interface.
	 */
	public void addPointToBlock() {
		// player 1 ;outside.
		int up1 = 0;
		int right1 = stageBlock[0].length - 4;
		int down1 = allBlockPath / 2 - (stageBlock.length - 4) - 1;
		int left1 = allBlockPath / 2 - 1;
		// player 2 ;inside.
		int up2 = 0;
		int right2 = stageBlock[0].length - 4;
		int down2 = allBlockPath / 2 - (stageBlock.length - 4) - 1;
		int left2 = allBlockPath / 2 - 1;
		for (int i = 0; i < stageBlock.length; i++) {
			for (int j = 0; j < stageBlock[0].length; j++) {
				if (stageBlock[i][j] == 1 && i == 0) {
					point1[up1] = new JLabel(normal_surface);
					p6_panelStage.add(point1[up1]);
					up1++;
				} else if (stageBlock[i][j] == 1
						&& j == stageBlock[0].length - 1) {
					point1[right1] = new JLabel(normal_surface);
					p6_panelStage.add(point1[right1]);
					right1++;
				} else if (stageBlock[i][j] == 1 && i == stageBlock.length - 1) {
					point1[down1] = new JLabel(normal_surface);
					p6_panelStage.add(point1[down1]);
					down1--;
				} else if (stageBlock[i][j] == 1 && j == 0) {
					point1[left1] = new JLabel(normal_surface);
					p6_panelStage.add(point1[left1]);
					left1--;
				} else if (stageBlock[i][j] == 1 && i == 1) {
					point2[up2] = new JLabel(normal_surface);
					p6_panelStage.add(point2[up2]);
					up2++;
				} else if (stageBlock[i][j] == 1
						&& j == stageBlock[0].length - 2) {
					point2[right2] = new JLabel(normal_surface);
					p6_panelStage.add(point2[right2]);
					right2++;
				} else if (stageBlock[i][j] == 1 && i == stageBlock.length - 2) {
					point2[down2] = new JLabel(normal_surface);
					p6_panelStage.add(point2[down2]);
					down2--;
				} else if (stageBlock[i][j] == 1 && j == 1) {
					point2[left2] = new JLabel(normal_surface);
					p6_panelStage.add(point2[left2]);
					left2--;
				} else if (stageBlock[i][j] == 11)
					p6_panelStage.add(new JLabel(new ImageIcon(this.getClass()
							.getResource("/images/curve1.png"))));
				else if (stageBlock[i][j] == 22)
					p6_panelStage.add(new JLabel(new ImageIcon(this.getClass()
							.getResource("/images/curve2.png"))));
				else if (stageBlock[i][j] == 33)
					p6_panelStage.add(new JLabel(new ImageIcon(this.getClass()
							.getResource("/images/curve4.png"))));
				else if (stageBlock[i][j] == 44)
					p6_panelStage.add(new JLabel(new ImageIcon(this.getClass()
							.getResource("/images/curve3.png"))));
				else if (stageBlock[i][j] == 2)
					p6_panelStage.add(new JLabel(new ImageIcon(this.getClass()
							.getResource("/images/goal.png"))));
				else if (stageBlock[i][j] == 3)
					p6_panelStage.add(new JLabel(new ImageIcon(this.getClass()
							.getResource("/images/normal.png"))));
				else
					p6_panelStage.add(new JLabel(nothing));
			}
		}
	}

	/**
	 * Move the winner's car forward.
	 * @param point the way for the car to move.
	 * @param distance the distance of the car.
	 * @param boosterIsOn the status of the car's booster.(on or not)
	 * @param car the winner's car.
	 * @param imCar the image of the car.
	 * @param bonus the bonus distance.
	 * @param lap the lap of the car.
	 * @param lap_label the label for showing car's lap.
	 * @param userName the name of the winner.
	 */
	public void move(final JLabel[] point, final int[] distance,
			boolean boosterIsOn, final RacingCar car, final ImageIcon imCar,
			final int bonus, final int[] lap, final JLabel lap_label,
			final String userName) {
		String s;
		if (rule.getClass() == DiceRule.class) {
			p6_battleLogField.add(String.format("%s rolls %s.  %s rolls %s.",
					userName1, p6_user1Result_label.getText(), userName2,
					p6_user2Result_label.getText()));
			if (boosterIsOn) {
				s = String.format(
						"%s wins and rushes by %d! with %d different bonus!",
						userName, car.getBoosterSpeed(), bonus).toString();
			} else {
				s = String.format(
						"%s wins and moves by %d! with %d different bonus!",
						userName, car.getSpeed(), bonus).toString();
			}
		} else {
			if (boosterIsOn) {
				s = String.format("%s wins and rushes by %d!", userName,
						car.getBoosterSpeed()).toString();
			} else {
				s = String.format("%s wins and moves by %d!", userName,
						car.getSpeed()).toString();
			}
		}
		p6_battleLogField.add(s);
		p6_battleLogField.select(p6_battleLogField.getItemCount() - 1);

		// move
		final int firstPoint = distance[0];
		if (boosterIsOn) {
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					p6_buttons.setEnabled(false);
					int i = firstPoint;
					for (; i < firstPoint + car.getBoosterSpeed() + bonus;) {
						final int index = i % (allBlockPath / 2 - 1);
						i++;
						point[index].setIcon(normal_surface);
						checkLap(point, i, lap, lap_label, userName, imCar);
						if (lap[0] == 4)
							break;
						final int nextIndex = i % (allBlockPath / 2 - 1);
						SwingUtilities.invokeLater(new Runnable() {
							@Override
							public void run() {
								point[nextIndex].setIcon(imCar);
							}
						});
						try {
							Thread.sleep(40);
						} catch (InterruptedException e) {
						}
						distance[0] = i;
					}
					p6_buttons.setEnabled(true);
				}
			});
			thread.start();
		} else {
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					p6_buttons.setEnabled(false);
					int i = firstPoint;
					for (; i < firstPoint + car.getSpeed() + bonus;) {
						final int index = i % (allBlockPath / 2 - 1);
						i++;
						point[index].setIcon(normal_surface);
						checkLap(point, i, lap, lap_label, userName, imCar);
						if (lap[0] == 4)
							break;
						final int nextIndex = i % (allBlockPath / 2 - 1);
						SwingUtilities.invokeLater(new Runnable() {
							@Override
							public void run() {
								point[nextIndex].setIcon(imCar);
							}
						});
						try {
							Thread.sleep(40);
						} catch (InterruptedException e) {
						}
						distance[0] = i;
					}
					p6_buttons.setEnabled(true);
				}
			});
			thread.start();
		}
	}

	/**
	 * Time pass for playing with bot mode.
	 * Decrease the booster time if the booster is on.
	 * Decrease the booster cooldown if the booster is not on.
	 * Automatic turn booster on for the bot.
	 */
	public void timePass() {
		if (booster1IsOn) {
			bTime1--;
			p6_1progressBar.setValue(bTime1);
			p6_1btnBooster.setText("Booster Left : " + bTime1);
			if (bTime1 == 0) {
				cTime1 = car1.getBoosterCooldown();
				bTime1 = car1.getBoosterTime();
				p6_1progressBar.setMaximum(car1.getBoosterCooldown());
				booster1IsOn = false;
				p6_1btnBooster.setText("CoolTime : " + cTime1);
			}
		} else {
			if (cTime1 > 0)
				cTime1--;
			if (cTime1 == 0) {
				p6_1btnBooster.setText("BOOSTER!");
				p6_1btnBooster.setEnabled(true);
				p6_1progressBar.setValue(car1.getBoosterCooldown() - cTime1);
				p6_1progressBar.setMaximum(car1.getBoosterTime());
			} else {
				p6_1btnBooster.setText("CoolTime : " + cTime1);
				p6_1progressBar.setValue(car1.getBoosterCooldown() - cTime1);
			}
		}

		if (booster2IsOn) {
			bTime2--;
			p6_2progressBar.setValue(bTime2);
			p6_2btnBooster.setText("Booster Left : " + bTime2);
			if (bTime2 == 0) {
				cTime2 = car2.getBoosterCooldown();
				bTime2 = car2.getBoosterTime();
				p6_2progressBar.setMaximum(car2.getBoosterCooldown());
				booster2IsOn = false;
				p6_2btnBooster.setText("CoolTime : " + cTime2);
			}
		} else {
			if (cTime2 > 0)
				cTime2--;
			if (cTime2 == 0) {
				// automatic turn on.
				booster2IsOn = true;
				p6_2btnBooster.setText("Booster Left : " + bTime2);
				p6_2progressBar.setValue(car2.getBoosterCooldown() - cTime2);
				p6_2progressBar.setMaximum(car2.getBoosterTime());
			} else {
				p6_2btnBooster.setText("CoolTime : " + cTime2);
				p6_2progressBar.setValue(car2.getBoosterCooldown() - cTime2);
			}
		}
	}

	/**
	 * Time pass for playing with multi player mode.
	 * Decrease the booster time if the booster is on.
	 * Decrease the booster cooldown if the booster is not on.
	 */
	public void timePassMuti() {
		if (booster1IsOn) {
			bTime1--;
			p6_1progressBar.setValue(bTime1);
			p6_1btnBooster.setText("Booster Left : " + bTime1);
			if (bTime1 == 0) {
				cTime1 = car1.getBoosterCooldown();
				bTime1 = car1.getBoosterTime();
				p6_1progressBar.setMaximum(car1.getBoosterCooldown());
				booster1IsOn = false;
				p6_1btnBooster.setText("CoolTime : " + cTime1);
			}
		} else {
			if (cTime1 > 0)
				cTime1--;
			if (cTime1 == 0) {
				p6_1btnBooster.setText("BOOSTER!");
				p6_1btnBooster.setEnabled(true);
				p6_1progressBar.setValue(car1.getBoosterCooldown() - cTime1);
				p6_1progressBar.setMaximum(car1.getBoosterTime());
			} else {
				p6_1btnBooster.setText("CoolTime : " + cTime1);
				p6_1progressBar.setValue(car1.getBoosterCooldown() - cTime1);
			}
		}

		if (booster2IsOn) {
			bTime2--;
			p6_2progressBar.setValue(bTime2);
			p6_2btnBooster.setText("Booster Left : " + bTime2);
			if (bTime2 == 0) {
				cTime2 = car2.getBoosterCooldown();
				bTime2 = car2.getBoosterTime();
				p6_2progressBar.setMaximum(car2.getBoosterCooldown());
				booster2IsOn = false;
				p6_2btnBooster.setText("CoolTime : " + cTime2);
			}
		} else {
			if (cTime2 > 0)
				cTime2--;
			if (cTime2 == 0) {
				p6_2btnBooster.setText("BOOSTER!");
				p6_2progressBar.setValue(car2.getBoosterCooldown() - cTime2);
				p6_2progressBar.setMaximum(car2.getBoosterTime());
			} else {
				p6_2btnBooster.setText("CoolTime : " + cTime2);
				p6_2progressBar.setValue(car2.getBoosterCooldown() - cTime2);
			}
		}
	}

	/**
	 * Check the lap of the car. If the lap is 4 then that user win the game and go to the result page.
	 * @param point the way for the car to move.
	 * @param distance the distance of the car.
	 * @param lap the lap of the car.
	 * @param lap_label the label for showing car's lap.
	 * @param userName the name of the user.
	 * @param imCar the image of the car.
	 */
	public void checkLap(JLabel[] point, int distance, int[] lap,
			JLabel lap_label, String userName, ImageIcon imCar) {
		lap[0] = distance / (allBlockPath / 2 - 1) + 1;
		if (lap[0] == 4) {
			point[distance % (allBlockPath / 2 - 1)].setIcon(imCar);
			lap_label.setText(userName + "  " + "WIN");
			JOptionPane.showMessageDialog(null, userName + " WIN!",
					" Winner !", JOptionPane.INFORMATION_MESSAGE);
			if (userName == userName1)
				initPage7(userName1, userName2);
			else
				initPage7(userName2, userName1);
			nextActionPerformed();
			// TODO inform user and go to the start page
		} else
			lap_label.setText(userName + "  " + (lap[0]) + "/3 LAP");

	}

	/**
	 * Set the client.
	 * @param client the client to be set.
	 */
	public void setClient(Client client) {
		this.client = client;
		bot = new Bot();
		p2_createButton.setEnabled(true);
		p2_joinButton.setEnabled(true);
		p2_onlineButton.setEnabled(false);
		client.addObserver(this);
		try {
			client.sendToServer(new Message("setid"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		if (arg1 instanceof Message) {
			Message message = (Message) arg1;
			String command = message.getCommand();
			int id_other = message.getID();
			String messageText = message.getMessage();
			if (command.equals("id") && id == 0) {
				id = id_other;
			}
			if (command.equals("setName") && id_other != id) {
				userName2 = messageText;
				System.out.println(userName1 + " " + userName2);
			}
			if (command.equals("setStage") && id_other != id) {
				selectedStage = messageText;
				stage = StageFactory.getInstance().createStage(messageText);
			}
			if (command.equals("setCar") && id_other != id) {
				car2 = RacingCarFactory.getInstance().createCar(messageText);
				imCar2 = new ImageIcon(this.getClass().getResource(
						"/images/inField" + car2.getName() + ".png"));
				if (isHost) {
					isStart = true;
				}
			}
			if (command.equals("setRule") && id_other != id) {
				if (messageText.equals("RPS")) {
					rule = new RPSRule();
				} else
					rule = new DiceRule();
			}
			if (command.equals("start") && id_other != id) {
				isStart = true;
			}
			if (command.equals("Other person disconnected")) {
				JOptionPane.showMessageDialog(null,
						"Connected Lost : Other person disconnected",
						"Announce", JOptionPane.WARNING_MESSAGE);
				try {
					Runtime.getRuntime().exec("java -jar PA7.jar");
					System.exit(0);
				} catch (IOException e) {
				}
			}
			if (command.equals("Server Full")) {
				JOptionPane.showMessageDialog(null,
						"Connected Lost : Server Full", "Announce",
						JOptionPane.WARNING_MESSAGE);
				p2_createButton.setEnabled(false);
				p2_joinButton.setEnabled(false);
				p2_onlineButton.setEnabled(true);
			}
			if (command.equals("hasRoom")) {
				JOptionPane.showMessageDialog(null, "Server already has room.",
						"Announce", JOptionPane.WARNING_MESSAGE);
				p2_createButton.setEnabled(false);
				p2_joinButton.setEnabled(false);
				p2_onlineButton.setEnabled(true);
				if (isHost)
					returnActionPerformed();
				else {
					returnActionPerformed();
					returnActionPerformed();
				}
				isHost = false;

			}
			if (command.equals("noRoom")) {
				JOptionPane.showMessageDialog(null, "No room in server.",
						"Announce", JOptionPane.WARNING_MESSAGE);
				p2_createButton.setEnabled(false);
				p2_joinButton.setEnabled(false);
				p2_onlineButton.setEnabled(true);
				if (isHost)
					returnActionPerformed();
				else {
					returnActionPerformed();
					returnActionPerformed();
				}
				isHost = false;
			}
			if (command.equals("wait")) {
				JOptionPane.showMessageDialog(null,
						"Waiting for other player.", "Announce",
						JOptionPane.WARNING_MESSAGE);
				if (isHost)
					returnActionPerformed();
				else {
					returnActionPerformed();
					returnActionPerformed();
				}
			}
			if (command.equals("sendDice") && id_other != id) {
				p6_user2Result_label.setText(messageText);
				p6_user1Result_label.setText(dice);
			}
			if (command.equals("sendRPS") && id_other != id) {
				if (messageText.equals("Rock")) {
					rps2 = RPS.ROCK;
					p6_user1Result_label.setIcon(((RPSRule) rule)
							.getImageIcon(rps1.toString(rps1)));
					p6_user2Result_label.setIcon(((RPSRule) rule)
							.getImageIcon(rps2.toString(rps2)));
				}
				if (messageText.equals("Paper")) {
					rps2 = RPS.PAPER;
					p6_user1Result_label.setIcon(((RPSRule) rule)
							.getImageIcon(rps1.toString(rps1)));
					p6_user2Result_label.setIcon(((RPSRule) rule)
							.getImageIcon(rps2.toString(rps2)));
				}
				if (messageText.equals("Scissors")) {
					rps2 = RPS.SCISSORS;
					p6_user1Result_label.setIcon(((RPSRule) rule)
							.getImageIcon(rps1.toString(rps1)));
					p6_user2Result_label.setIcon(((RPSRule) rule)
							.getImageIcon(rps2.toString(rps2)));
				}
			}
			if (command.equals("startAll")) {
				startAll = true;
			}
			if (command.equals("clickBooster") && id_other != id) {
				booster2IsOn = true;
				p6_2btnBooster.setEnabled(false);
				p6_2btnBooster.setText("Booster Left : " + bTime2);
			}
			if (command.equals("confirmRoll")) {
				rollButton.setEnabled(true);
				int different = Integer
						.parseInt(p6_user1Result_label.getText())
						- Integer.parseInt(p6_user2Result_label.getText());
				if (different > 0) // user 1 win.
					move(point1, distance1, booster1IsOn, car1, imCar1,
							Math.abs(different), lap1, lap1_label, userName1);
				else if (different < 0) // user 2 win.
					move(point2, distance2, booster2IsOn, car2, imCar2,
							Math.abs(different), lap2, lap2_label, userName2);
				timePassMuti();
			}
			if (command.equals("confirmRPS")) {
				rockButton.setEnabled(true);
				paperButton.setEnabled(true);
				scissorsButton.setEnabled(true);
				RPS winner = ((RPSRule) rule).play(rps1, rps2);
				if (winner == rps1) // user 1 win.
					move(point1, distance1, booster1IsOn, car1, imCar1, 0,
							lap1, lap1_label, userName1);
				else if (winner == rps2) // user 2 win.
					move(point2, distance2, booster2IsOn, car2, imCar2, 0,
							lap2, lap2_label, userName2);
				else
					p6_battleLogField.add("DRAW");
				timePassMuti();
			}
		}
	}
}
